/**
 * 默认情况下，类型检查器认为 null与 undefined可以赋值给任何类型
 * --strictNullChecks标记可以解决此错误：当你声明一个变量时，它不会自动地包含 null或 undefined。
 */
let sn: string | null = 'bar';
sn = null; // 可以
// sn = undefined; // error, 'undefined'不能赋值给'string | null'

// let s = 'foo';
// s = null; // 错误, 'null'不能赋值给'string'

/**
 * 可选参数和可选属性都会被加上undefined
 */
function add(x: string, y?: string) {
  return x + y;
}
console.log(add('Hello '));
console.log(add('Hello ', 'World!'));

class Person {
  name: string

  age?: number

  constructor(name: string) {
    this.name = name;
  }
}
const person = new Person('Dell');
person.name = 'Lily';
// person.name = undefined; // 发生错误
person.age = 12;
person.age = undefined;
console.log(person);

/**
 * 类型保护和类型断言
 */
function getName(name: string | null): string {
  return name || 'Please input your name!';
}
console.log(getName(null));

/**
 * 本例使用了嵌套函数，因为编译器无法去除嵌套函数的null（除非是立即调用的函数表达式）。
 * 因为它无法跟踪所有对嵌套函数的调用，尤其是你将内层函数做为外层函数的返回值。
 * 如果无法知道函数在哪里被调用，就无法知道调用时 name的类型。
 * @param name
 * @returns
 */
function fixed(name: string | null): string {
  function postfix(epithet: string) {
    return `${name!.charAt(0)}.  the ${epithet}`; // ok
  }
  name = name || 'Bob';
  return postfix('great');
}
console.log(fixed('Tom'));
